﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Collections.Generic;
using System.Reflection;

namespace Moon.Sql
{
    /// <summary>
    /// 表达式解析
    /// </summary>
    internal class ExpressionProvide : IExpression
    {
        //数据库方言
        public ISqlDialect SqlDialect = null;
        //参数
        public DynamicParameters Parameters = null;
        //是否需要前缀
        public bool IsPrefix = false;
        //是否转义列名
        public bool IsQuote = true;
        //是否需要别名
        public bool IsAlias = true;
        //参数前缀
        public const string ParameterName = "param";
        //参数下标
        public int Index = 0;
        //表达式实体类
        public Dictionary<Type, MapperTable> dictMapperTable = null;
        //需要解析的表达式
        public Expression MasterExpression = null;
        //是否是子查询
        public bool IsSubquery = false;

        public ExpressionProvide(ISqlDialect _SqlDialect, params MapperTable[] _tables)
        {
            if (_tables == null || _tables.Length == 0) throw new ArgumentNullException("the parameter is empty");
            LoadMappingTable(_tables);
            this.SqlDialect = _SqlDialect;
        }

        #region MappingTable
        public void AppendMappingTable(MapperTable item)
        {
            if (!dictMapperTable.ContainsKey(item.EntityType))
            {
                dictMapperTable.Add(item.EntityType, item);
            }
        }

        private void LoadMappingTable(MapperTable[] tables)
        {
            if (tables == null || tables.Length == 0) throw new Exception("the parameter is empty");
            dictMapperTable = new Dictionary<Type, MapperTable>();
            foreach (var item in tables)
            {
                if (!dictMapperTable.ContainsKey(item.EntityType))
                {
                    dictMapperTable.Add(item.EntityType, item);
                }
            }
        }
        #endregion MappingTable

        /// <summary>
        /// 表达式解析入口路由
        /// </summary>
        /// <param name="exp">表达式</param>
        /// <param name="isPrefix">是否需要前缀</param>
        /// <param name="isQuote">是否转义列名</param>
        /// <param name="isAlias">是否需要别名</param>
        /// <returns></returns>
        public SqlBuilderResult ExpressionRouter(Expression exp, bool isPrefix = false, bool isQuote = true, bool isAlias = true)
        {
            if (exp == null) return null;
            MasterExpression = exp;
            IsPrefix = isPrefix;
            IsQuote = isQuote;
            IsAlias = isAlias;
            Parameters = new DynamicParameters();
            string sql = Resolve(exp);
            return new SqlBuilderResult()
            {
                Sql = sql,
                DynamicParameters = Parameters
            };
        }

        #region Resolve
        public string Resolve(Expression exp)
        {
            if (exp is BinaryExpression)
            {
                //表示具有二进制运算符的表达式
                return new BinarExpressionProvider(this).Resolve(exp);
            }
            else if (exp is ConstantExpression)
            {
                //表示具有常数值的表达式
                return new ConstantExpressionProvider(this).Resolve(exp);
            }
            else if (exp is LambdaExpression)
            {
                //介绍 lambda 表达式。 它捕获一个类似于 .NET 方法主体的代码块
                return new LambdaExpressionProvider(this).Resolve(exp);
            }
            else if (exp is MemberExpression)
            {
                //表示访问字段或属性
                return new MemberExpressionProvider(this).Resolve(exp);
            }
            else if (exp is MethodCallExpression)
            {
                //表示对静态方法或实例方法的调用
                return new MethodCallExpressionProvider(this).Resolve(exp);
            }
            else if (exp is NewArrayExpression)
            {
                //表示创建一个新数组，并可能初始化该新数组的元素
                return new NewArrayExpressionProvider(this).Resolve(exp);
            }
            else if (exp is ParameterExpression)
            {
                //表示一个命名的参数表达式。
                return new ParameterExpressionProvider(this).Resolve(exp);
            }
            else if (exp is UnaryExpression)
            {
                //表示具有一元运算符的表达式
                return new UnaryExpressionProvider(this).Resolve(exp);
            }
            else if (exp is NewExpression)
            {
                //表示构造函数调用
                return new NewExpressionProvider(this).Resolve(exp);
            }
            return "";
        }
        #endregion Resolve

        /// <summary>
        /// 获取方法参数值
        /// </summary>
        /// <param name="mce"></param>
        /// <returns></returns>
        public List<object> GetMethodCallExpressionVal(MethodCallExpression mce, bool isHaveFirst = true)
        {
            //mce.Object为null时，第1个参数是表达式
            bool flag = mce.Object == null;
            List<object> list = new List<object>();
            if (mce.Arguments?.Count > 0)
            {
                foreach (var item in mce.Arguments)
                {
                    if (flag && isHaveFirst)
                    {
                        flag = false;
                        continue;
                    }
                    switch (item.NodeType)
                    {
                        case ExpressionType.Call:
                        case ExpressionType.Constant:
                            //常量值访问
                            list.Add((item as ConstantExpression).Value);
                            break;
                        case ExpressionType.Add:
                        case ExpressionType.MemberAccess:
                            //属性访问
                            list.Add(Expression.Lambda(item).Compile().DynamicInvoke());
                            break;
                        case ExpressionType.NewArrayInit:
                            break;
                        default:
                            throw new Exception("unsupported expression");
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public string GetParamVal(Expression exp)
        {
            if (exp is ConstantExpression)
            {
                return new ConstantExpressionProvider(this).Resolve(exp);
            }
            else
            {
                return Resolve(exp);
            }
        }

        /// <summary>
        /// 设置参数
        /// </summary>
        /// <param name="val"></param>
        public void SetParameter(object val)
        {
            Index++;
            string paramName = ParameterName + (Index);
            Parameters.Add(paramName, val);
        }

        /// <summary>
        /// 获取当前参数名
        /// </summary>
        /// <returns></returns>
        public string GetParamName()
        {
            return SqlDialect.ParameterPrefix + ParameterName + (Index);
        }

        /// <summary>
        /// 获取实体类数据库表中列名
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="colName"></param>
        /// <returns></returns>
        public string GetColumnName(Type entityType, string colName)
        {
            if (dictMapperTable.ContainsKey(entityType))
            {
                if (dictMapperTable[entityType].PropertiesDict.ContainsKey(colName))
                {
                    colName = dictMapperTable[entityType].PropertiesDict[colName].ColumnName;
                }
            }
            return colName;
        }

        /// <summary>
        /// 解析 i=>i.id + 1
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="isPrefix"></param>
        /// <param name="isQuote"></param>
        /// <returns></returns>
        public SqlBuilderResult ExpressionFieldValue(Expression exp, bool isPrefix = false, bool isQuote = true)
        {
            UnaryExpression ue = exp as UnaryExpression;
            if (ue.Operand.NodeType != ExpressionType.Equal)
            {
                IsPrefix = isPrefix;
                IsQuote = isQuote;
                Parameters = new DynamicParameters();
                BinaryExpression be = ue.Operand as BinaryExpression;
                ExpressionType type = be.NodeType;
                StringBuilder leftSql = new StringBuilder();
                string leftResult = Resolve(be.Left);
                leftSql.Append(leftResult).Append("=").Append(leftResult);
                leftSql.Append(ExpressionTypeCast(type));
                leftSql.Append(Resolve(be.Right));
                return new SqlBuilderResult()
                {
                    Sql = leftSql.ToString(),
                    DynamicParameters = Parameters
                };
            }
            var ep = ExpressionRouter(exp, isPrefix, isQuote);
            ep.Sql = CommonUtils.TrimEndString(ep.Sql.Replace("is null", "=null").TrimStart('('), ")");
            return ep;
        }

        #region 表达式类型转换
        /// <summary>
        /// 表达式类型转换
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public string ExpressionTypeCast(ExpressionType type)
        {
            switch (type)
            {
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    return " and ";
                case ExpressionType.Equal:
                    return " = ";
                case ExpressionType.GreaterThan:
                    return " > ";
                case ExpressionType.GreaterThanOrEqual:
                    return " >= ";
                case ExpressionType.LessThan:
                    return " < ";
                case ExpressionType.LessThanOrEqual:
                    return " <= ";
                case ExpressionType.NotEqual:
                    return " <> ";
                case ExpressionType.Or:
                case ExpressionType.OrElse:
                    return " or ";
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return " + ";
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return " - ";
                case ExpressionType.Divide:
                    return " / ";
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return " * ";
                case ExpressionType.Modulo:
                case ExpressionType.ModuloAssign:
                    return " % ";
                default:
                    return null;
            }
        }

        /// <summary>
        /// 值类型转换
        /// </summary>
        /// <param name="_value"></param>
        /// <returns></returns>
        public object GetValueType(object _value)
        {
            //#2022.02.04
            //if (_value == null) return null;
            var _type = _value.GetType().Name;
            switch (_type)
            {
                case "Decimal": return Convert.ToDecimal(_value);
                case "Int32": return _value;
                case "DateTime": return _value;
                case "String": return _value?.ToString();
                case "Char": return Convert.ToChar(_value);
                case "Boolean": return _value;
                default: return _value;
            }
        }
        #endregion 表达式类型转换
    }
}